#include "cvutils.h"
#include "Def.h"
#include <qdebug.h>
#include <qfileinfo.h>
#include <qimage.h>
#include <unordered_set>
#include <QFile>
#include <QRegularExpression>

cv::Mat CvUtils::tableStructure::eraseRegions(cv::Mat &image, const json &data)
{
    // 解析每个文本区域
    for (const auto& obj : data["text_objects"]) {
        std::vector<cv::Point> polygon;

        // 构建多边形顶点坐标
        for (const auto& pt : obj["box"]) {
            int x = pt[0].get<int>();
            int y = pt[1].get<int>();
            polygon.emplace_back(x, y);
        }

        // 创建填充掩模
        cv::Mat mask = cv::Mat::zeros(image.size(), CV_8UC1);
        std::vector<std::vector<cv::Point>> contours = {polygon};
        fillPoly(mask, contours, cv::Scalar(255));

        // 高级擦除策略（三选一）
        // 1. 白色填充
        //image.setTo(cv::Scalar(255, 255, 255), mask);

        // 2. 黑色填充
        // image.setTo(Scalar(0, 0, 0), mask);

        // 3. 智能修复
        cv::Mat inpainted;
        inpaint(image, mask, inpainted, 3, cv::INPAINT_TELEA);
        inpainted.copyTo(image);
    }
    return image;
}


// 表格结构识别主函数实现
json CvUtils::tableStructure::exportToJson(const std::string& imgPath, const json& textInfo) {
    // 图像读取与预处理
    cv::Mat img = cv::imread(imgPath);  // 读取原始图像
    eraseRegions(img, textInfo);        // 擦除文本区域

    // === 图像预处理阶段 ===
    cv::Mat gray, erod, blur;
    cvtColor(img, gray, cv::COLOR_BGR2GRAY);  // 转换为灰度图

    // 形态学处理：腐蚀操作
    int erodeSize = gray.cols   / 300;    // 动态计算核尺寸
    erodeSize = erodeSize % 2 == 0 ? erodeSize + 1 : erodeSize;
    cv::Mat element = getStructuringElement(cv::MORPH_RECT, cv::Size(erodeSize, erodeSize));
    erode(gray, erod, element);

    // 高斯模糊降噪
    int blurSize = gray.cols  / 200;
    if (blurSize % 2 == 0) blurSize++;
    GaussianBlur(erod, blur, cv::Size(blurSize, blurSize), 0, 0);

    // 自适应阈值二值化
    cv::Mat thresh = gray.clone();
    adaptiveThreshold(~gray, thresh, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 15, -2);

    // === 表格线检测阶段 ===
    int scale = 20;  // 比例因子
    cv::Mat horizontal = thresh.clone();
    cv::Mat vertical = thresh.clone();

    // 水平线检测
    cv::Mat horizontalStructure = getStructuringElement(cv::MORPH_RECT, cv::Size(horizontal.cols/scale,   1));
    erode(horizontal, horizontal, horizontalStructure);
    dilate(horizontal, horizontal, horizontalStructure);

    // 垂直线检测
    cv::Mat verticalStructure = getStructuringElement(cv::MORPH_RECT, cv::Size(1, vertical.rows/scale));
    erode(vertical, vertical, verticalStructure);
    dilate(vertical, vertical, verticalStructure);

    // test
    // cv::namedWindow("horizontal", cv::WINDOW_NORMAL);
    // cv::imshow("horizontal", horizontal);
    // cv::namedWindow("vertical", cv::WINDOW_NORMAL);
    // cv::imshow("vertical", vertical);

    // === 网格特征提取 ===
    cv::Mat mask = horizontal + vertical;          // 合并所有线段
    cv::Mat joints;                                // 交叉点检测
    bitwise_and(horizontal, vertical, joints); // 水平线与垂直线交集

    // 调试显示
    //cv::namedWindow("joints", cv::WINDOW_NORMAL);
    //imshow("joints", joints);

    // === 轮廓分析阶段 ===
    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(mask, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE, cv::Point(0, 0));

    std::vector<std::vector<cv::Point> > contours_poly(contours.size());
    std::vector<cv::Rect> boundRect(contours.size());
    std::vector<cv::Mat> rois;

    // 遍历所有轮廓
    for (size_t i = 0; i < contours.size();  i++)
    {
        double area = contourArea(contours[i]);
        // 面积过滤小轮廓
        if (area < 100) continue;

        // 多边形逼近
        approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 3, true);
        // 获取边界矩形
        boundRect[i] = boundingRect(cv::Mat(contours_poly[i]));

        // 提取交叉点区域
        cv::Mat roi = joints(boundRect[i]);
        std::vector<std::vector<cv::Point> > joints_contours;
        findContours(roi, joints_contours, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);

        // 合格区域需包含至少4个交叉点
        if (joints_contours.size()  <= 4) continue;

        // 保存候选区域
        rois.push_back(img(boundRect[i]).clone());
    }

    // 清理无效矩形区域
    std::vector<cv::Rect>::iterator it;
    for(it = boundRect.begin();  it != boundRect.end();  ){
        if(it->width == 0 && it->height == 0)
            it = boundRect.erase(it);
        else
            ++it;
    }

    // === 网格结构分析 ===
    // 1. 提取所有交点坐标
    std::vector<cv::Point> jointPoints;
    for (int y = 0; y < joints.rows;  y++) {
        for (int x = 0; x < joints.cols;  x++) {
            if (joints.at<uchar>(y,  x) > 0) {
                jointPoints.emplace_back(x,  y);
            }
        }
    }

    // 2. 坐标聚类（合并邻近点）
    const int CLUSTER_THRESHOLD = 10; // 像素距离阈值
    auto clusterPoints = [](std::vector<int>& coords) {
        std::sort(coords.begin(),  coords.end());
        std::vector<int> clustered;
        if (coords.empty())  return clustered;

        int current = coords[0];
        clustered.push_back(current);

        for (int i = 1; i < coords.size();  i++) {
            if (coords[i] - current > CLUSTER_THRESHOLD) {
                current = coords[i];
                clustered.push_back(current);
            }
        }
        return clustered;
    };

    // 3. 分离并聚类X/Y坐标
    std::vector<int> xCoords, yCoords;
    for (const auto& pt : jointPoints) {
        xCoords.push_back(pt.x);
        yCoords.push_back(pt.y);
    }

    std::vector<int> uniqueXs = clusterPoints(xCoords);
    std::vector<int> uniqueYs = clusterPoints(yCoords);

    // 4. 构建网格映射
    int rows = uniqueYs.size()  - 1;
    int cols = uniqueXs.size()  - 1;

    // 文本对象处理
    struct TextObject {
        cv::Rect bbox;
        std::string text;
    };
    std::vector<TextObject> textObjs;
    for (const auto& obj : textInfo["text_objects"]) {
        std::vector<cv::Point> polygon;
        for (const auto& pt : obj["box"]) {
            polygon.emplace_back(pt[0],  pt[1]);
        }
        textObjs.push_back({cv::boundingRect(polygon),
                            obj["text"].get<std::string>()});
    }

    // 单元格内容容器
    struct CellContent {
        std::vector<TextObject> texts;
    };
    std::vector<std::vector<CellContent>> cells(rows,
                                                std::vector<CellContent>(cols));

    // 文本分配到单元格
    for (const auto& text : textObjs) {
        const cv::Point center(text.bbox.x  + text.bbox.width/2,
                               text.bbox.y  + text.bbox.height/2);

        // 寻找对应列
        int colIdx = -1;
        for (size_t c=0; c < uniqueXs.size()-1;  ++c) {
            if (center.x >= uniqueXs[c] && center.x < uniqueXs[c+1]) {
                colIdx = c;
                break;
            }
        }

        // 寻找对应行
        int rowIdx = -1;
        for (size_t r=0; r < uniqueYs.size()-1;  ++r) {
            if (center.y >= uniqueYs[r] && center.y < uniqueYs[r+1]) {
                rowIdx = r;
                break;
            }
        }

        if (rowIdx >=0 && colIdx >=0)
            cells[rowIdx][colIdx].texts.push_back(text);
    }

    // 多行文本排序合并
    auto requiresNoSpace = [](char last, char first) {
        // 中文、日文、韩文字符判断
        if ((last & 0x80) || (first & 0x80)) return true;
        // 标点符号判断
        const std::string punct = ",.;:?!)]}~$";
        return punct.find(last)  != std::string::npos;
    };

    json result;
    result["grid_size"] = {rows, cols};
    json cellArray = json::array();

    for (int r=0; r<rows; ++r) {
        for (int c=0; c<cols; ++c) {
            auto& cell = cells[r][c];
            std::string mergedText;

            // 多文本排序
            std::sort(cell.texts.begin(),  cell.texts.end(),
                      [](const TextObject& a, const TextObject& b) {
                          const int vertThreshold = a.bbox.height  / 2;
                          if (std::abs(a.bbox.y  - b.bbox.y)  > vertThreshold)
                              return a.bbox.y  < b.bbox.y;
                          return a.bbox.x  < b.bbox.x;
                      });

            // 智能合并
            for (size_t i=0; i<cell.texts.size();  ++i) {
                if (!mergedText.empty()  &&
                    !requiresNoSpace(mergedText.back(),
                                     cell.texts[i].text.front()))  {
                    mergedText += " ";
                }
                mergedText += cell.texts[i].text;
            }

            // 构建输出
            json cellJson;
            cellJson["row"] = r;
            cellJson["col"] = c;
            cellJson["value"] = mergedText;
            cellArray.push_back(cellJson);
        }
    }

    result["cells"] = cellArray;
    return result;
}

void CvUtils::objectCounter::slot_reCount() {
    qDebug()<<"收到sig_reCount";
    ObjectInfo result;
    cv::Mat src = m_image.clone();

    // 预处理（两种方法共用）
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3), cv::Point(-1, -1));
    morphologyEx(src, src, cv::MORPH_OPEN, kernel);
    cv::Mat src_gray;
    cvtColor(src, src_gray, cv::COLOR_BGR2GRAY);
    cv::Mat src_binary;
    threshold(src_gray, src_binary, 100, 255, cv::THRESH_OTSU);

    if (m_markType == markType::BasedOnEdge) {
        cv::TickMeter tm;
        tm.start();
        // 基于边缘的方法
        cv::Mat src_distance;
        distanceTransform(src_binary, src_distance, cv::DIST_L2, 3);
        normalize(src_distance, src_distance, 0, 1, cv::NORM_MINMAX);
        threshold(src_distance, src_distance, 0.4, 1, cv::THRESH_BINARY);

        src_distance.convertTo(src_distance,  CV_8UC1);
        std::vector<std::vector<cv::Point>> contours;
        cv::findContours(src_distance, contours, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);

        cv::Mat markers = cv::Mat::zeros(src.size(),  CV_32S);
        for (size_t t = 0; t < contours.size();  t++) {
            drawContours(markers, contours, static_cast<int>(t), cv::Scalar(static_cast<int>(t) + 1), -1);
        }
        // 执行分水岭算法
        cv::Mat labels;
        watershed(src, markers);
        labels = markers.clone();

        tm.stop();
        qDebug()<<"markType::BasedOnEdge:"<<tm.getTimeMilli()<<"ms";

        // 分析分水岭结果并填充ObjectInfo
        processWatershedResult(labels, result);
    }
    else { // BasedOnArea
        // 基于区域的方法
        cv::TickMeter tm;
        tm.start();
        cv::Mat foreground, background, unknown;
        dilate(src_binary, background, kernel, cv::Point(-1, -1), 3);

        cv::Mat src_distance;
        distanceTransform(src_binary, src_distance, cv::DIST_L2, 3);
        normalize(src_distance, src_distance, 0, 255, cv::NORM_MINMAX);

        double minVal, maxVal;
        minMaxIdx(src_binary, &minVal, &maxVal);
        threshold(src_distance, foreground, 0.4 * maxVal, 255, cv::THRESH_BINARY);
        foreground.convertTo(foreground,  CV_8U);

        unknown = background - foreground;
        cv::Mat markers = cv::Mat(src.size(), CV_32S);
        connectedComponents(foreground, markers, 8/*, CV_32S*/);
        markers += 1;

        for (int i = 0; i < unknown.rows;  i++) {
            for (int j = 0; j < unknown.cols;  j++) {
                if (((int)unknown.at<uchar>(i,  j)) == 255) {
                    markers.at<signed int>(i,  j) = 0;
                }
            }
        }

        // 执行分水岭算法
        cv::Mat labels;
        watershed(src, markers);
        labels = markers.clone();

        tm.stop();
        qDebug()<<"markType::BasedOnArea:"<<tm.getTimeMilli()<<"ms";

        // 分析分水岭结果并填充ObjectInfo
        processWatershedResult(labels, result);
    }

    // 发射信号
    emit reCounted(result);
}

void CvUtils::objectCounter::slot_initImage(const cv::Mat &image){
    qDebug()<<"收到sig_initImage";
    if (image.empty())  {
        qWarning() << "传入的图像为空!";
        return;
    }
    m_image = image.clone();
}

void CvUtils::objectCounter::slot_setMarkType(markType type) {
    qDebug()<<"收到sig_setMarkType";
    m_markType = type;
    slot_reCount();
}

void CvUtils::objectCounter::processWatershedResult(const cv::Mat &labels, ObjectInfo &result) {
    cv::TickMeter tm;
    tm.start();
    result.total = 0;
    result.positionMap.clear();
    result.rMap.clear();

    // 找出所有唯一标记（忽略边界-1和背景0）
    std::unordered_set<int> uniqueLabels;
    for (int i = 0; i < labels.rows; i++) {
        for (int j = 0; j < labels.cols; j++) {
            int label = labels.at<int>(i, j);
            if (label > 0) { // 忽略背景和边界
                uniqueLabels.insert(label);
            }
        }
    }

    // 对每个物体计算几何属性
    for (int label : uniqueLabels) {
        // 创建该标签的掩码
        cv::Mat mask = (labels == label);

        // 计算轮廓
        std::vector<std::vector<cv::Point>> contours;
        findContours(mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

        if (!contours.empty()) {
            // 计算最小外接圆
            cv::Point2f center;
            float radius;
            minEnclosingCircle(contours[0], center, radius);

            // 存储结果
            result.positionMap.emplace_back(cvRound(center.x), cvRound(center.y));
            result.rMap.push_back(radius);
            result.total++;
        }
    }
    tm.stop();
    qDebug()<<"processWatershedResult:"<<tm.getTimeMilli()<<"ms";
}

CvUtils::cardCornerDetector::cardCornerDetector()
{
    registerMetaTypes();
    initSlots();
    // 在cardCornerDetector的构造函数中打印归属线程：
    qDebug() << "cardCornerDetector created in thread:" << QThread::currentThreadId();

    // 1. 移除主线程的 m_pythonProcess 初始化，改为在工作线程初始化
    m_pythonProcess = nullptr; // 先置空，后续在 initPythonProcess 中创建

    // 2. 保留其他配置（Python 路径、脚本路径），但不操作 QProcess
    m_pythonExePath = "D:/pythonsoft/python.exe";
    m_inferScriptPath = "D:/Qt_Projects/GreatScanner/keypoint_detection/infer_yolov8.py";
}

CvUtils::cardCornerDetector::~cardCornerDetector()
{
    qDebug() << "[~cardCornerDetector] 析构线程:" << QThread::currentThreadId();
    qDebug() << "[~cardCornerDetector] 归属线程:" << this->thread()->currentThreadId();

    // 仅在未删除时释放Python进程（避免双重释放）
    if (m_pythonProcess && !m_pythonProcessDeleted) {
        if (m_pythonProcess->state() == QProcess::Running) {
            m_pythonProcess->terminate();
            m_pythonProcess->waitForFinished(1000);
        }
        delete m_pythonProcess;
        m_pythonProcess = nullptr;
    }

    // 清理临时文件（双重保险）
    QFile::remove(m_frontTempImgPath);
    QFile::remove(m_backTempImgPath);
}

void CvUtils::cardCornerDetector::slot_loadModel(const QString &modelPath)
{
    qDebug()<<"收到sig_loadModel";
    try {
        // 3. 保存模型路径，标记文件有效
        m_modelPath = modelPath;
        m_modelFileValid = true;

        // 4. 如果Python进程未初始化，先初始化
        if (!m_pythonProcess) {
            initPythonProcess();
        } else if (m_pythonProcessReady) {
            // 如果进程已就绪，直接发送加载命令
            sendLoadModelCommand();
        }

    } catch (const std::exception& e) {
        emit sig_modelLoaded(false, QString("模型加载异常: %1").arg(e.what()));
        m_modelFileValid = false;
    }
}

void CvUtils::cardCornerDetector::slot_detect(const cv::Mat& frontImage, const cv::Mat& backImage)
{
    qDebug() << "slot_detect running in thread:" << QThread::currentThreadId();

    // 检查模型是否已加载
    if (!m_modelLoaded) {
        emit sig_errorOccurred("检测失败: 模型未加载完成");
        return;
    }

    // 检查Python进程状态
    if (!m_pythonProcess || m_pythonProcess->state() != QProcess::Running) {
        emit sig_errorOccurred("检测失败: Python进程未运行");
        return;
    }

    if (frontImage.empty() || backImage.empty()) {
        emit sig_errorOccurred("检测失败: 输入图像为空");
        return;
    }

    m_currentFrontImage = frontImage.clone();
    m_currentBackImage = backImage.clone();

    try {
        // 保存图像为临时文件
        m_frontTempImgPath = saveMatToTempFile(frontImage, "front_card");
        m_backTempImgPath = saveMatToTempFile(backImage, "back_card");

        if (m_frontTempImgPath.isEmpty() || m_backTempImgPath.isEmpty()) {
            return;
        }

        // 发送检测命令给Python进程
        m_currentCommand = CommandType::Detect;
        json cmd;
        cmd["command"] = "detect";
        cmd["front_img"] = m_frontTempImgPath.toStdString();
        cmd["back_img"] = m_backTempImgPath.toStdString();
        QString cmdStr = QString::fromStdString(cmd.dump()) + "\n";

        m_pythonProcess->write(cmdStr.toUtf8());

    } catch (const std::exception& e) {
        emit sig_errorOccurred(QString("检测过程异常: %1").arg(e.what()));
        QFile::remove(m_frontTempImgPath);
        QFile::remove(m_backTempImgPath);
    }
}

void CvUtils::cardCornerDetector::slot_exitProcess()
{
    qDebug() << "[slot_exitProcess] 执行线程:" << QThread::currentThreadId();
    if (m_pythonProcess && !m_pythonProcessDeleted) {
        if (m_pythonProcess->state() == QProcess::Running) {
            // 关键：发送Python脚本能识别的退出命令（而非直接kill）
            // 匹配Python交互模式的exit命令处理逻辑
            json exitCmd;
            exitCmd["command"] = "exit";
            QString cmdStr = QString::fromStdString(exitCmd.dump()) + "\n";
            m_pythonProcess->write(cmdStr.toUtf8());

            // 等待Python进程正常退出（最多3秒）
            if (m_pythonProcess->waitForFinished(3000)) {
                qDebug() << "[slot_exitProcess] Python进程正常退出";
            } else {
                qWarning() << "[slot_exitProcess] Python进程超时，强制终止";
                m_pythonProcess->terminate();
                m_pythonProcess->waitForFinished(1000);
            }
        }
        // 仅标记为已处理，不删除（析构函数统一删除）
        m_pythonProcessDeleted = true;
    }

    // 清理临时文件
    QFile::remove(m_frontTempImgPath);
    QFile::remove(m_backTempImgPath);

    // 发送“退出完成”信号，通知主线程可继续析构
    emit sig_exitFinished();
}

void CvUtils::cardCornerDetector::onPythonFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
    // 仅处理进程异常退出的情况
    if (exitStatus != QProcess::NormalExit || exitCode != 0) {
        QString errorMsg = QString("Python进程异常退出（代码：%1）").arg(exitCode);
        errorMsg += "\n" + QString::fromUtf8(m_pythonProcess->readAllStandardError());
        emit sig_errorOccurred(errorMsg);

        // 尝试重启进程（如果模型文件有效）
        if (m_modelFileValid) {
            initPythonProcess();
        }
    }
}

// 在 cvutils.cpp 中修改 initPythonProcess 函数
void CvUtils::cardCornerDetector::initPythonProcess()
{
    qDebug() << "[initPythonProcess] 开始执行，当前线程:" << QThread::currentThreadId();
    if (m_pythonProcess) {
        qDebug() << "[initPythonProcess] m_pythonProcess 已初始化，无需重复创建";
        return;
    }

    m_pythonProcess = new QProcess(this);
    if (!m_pythonProcess) {
        qCritical() << "[initPythonProcess] 创建 QProcess 失败！";
        emit sig_errorOccurred("初始化 Python 进程失败: 内存不足");
        return;
    }

    // 配置Python进程
    m_pythonProcess->setReadChannel(QProcess::StandardOutput);
    m_pythonProcess->setProcessChannelMode(QProcess::MergedChannels);

    // 连接readyRead信号处理实时输出（包括进度和命令结果）
    connect(m_pythonProcess, &QProcess::readyRead, this, [this]() {
        QByteArray data = m_pythonProcess->readAll();
        QString output = QString::fromUtf8(data);
        qDebug() << "[Python Output]:" << output;

        // 分割多行输出（可能一次读取多个JSON对象，用换行分隔）
        QStringList lines = output.split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
        for (const QString& line : lines) {  // 逐行解析，避免JSON格式错误
            QString cleanLine = line.trimmed();  // 去除首尾空白和特殊字符
            try {
                json result = json::parse(cleanLine.toStdString());

                // 1. 处理进度信息（原逻辑保留）
                if (result.contains("progress")) {
                    int pct = result["progress"].get<int>();
                    QString msg = QString::fromStdString(result["message"].get<std::string>());
                }
                // 2. 新增：处理命令执行结果（包括模型加载成功）
                else if (result.contains("status")) {
                    if (result["status"] == "error") {
                        emit sig_errorOccurred(QString::fromStdString(result["message"]));
                        continue;  // 错误信息处理后继续解析其他行
                    }

                    // 处理模型加载成功的结果
                    if (result["command"] == "load_model" && result["status"] == "success") {
                        m_modelLoaded = true;
                        emit sig_modelLoaded(true, QString::fromStdString(result["message"]));
                    }
                    // 处理检测结果（如果需要，保持原逻辑）
                    else if (result["command"] == "detect" && result["status"] == "success") {
                        std::vector<CardDetectionResult> fresults = parseJsonResults(result["front"], m_currentFrontImage);
                        std::vector<CardDetectionResult> bresults = parseJsonResults(result["back"], m_currentBackImage);

                        emit sig_detectionVisualized(
                            drawResults(m_currentFrontImage, fresults),
                            drawResults(m_currentBackImage, bresults)
                            );
                        emit sig_detectionFinished(fresults, bresults);
                    }
                }
            } catch (...) {
                // 非JSON格式的输出（如Python打印的调试信息），忽略
                qDebug() << "[Python 非JSON输出]:" << line;
            }
        }
    });

    // 连接进程结束信号
    connect(m_pythonProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
            this, &cardCornerDetector::onPythonFinished,
            Qt::QueuedConnection);

    // 启动Python进程（以交互模式运行）
    QStringList args;
    args << m_inferScriptPath << "--interactive"; // 传递交互模式参数
    m_pythonProcess->start(m_pythonExePath, args);

    if (!m_pythonProcess->waitForStarted(2000)) {
        QString errorMsg = "Python进程启动失败: " + m_pythonProcess->errorString();
        qCritical() << errorMsg;
        emit sig_errorOccurred(errorMsg);
        delete m_pythonProcess;
        m_pythonProcess = nullptr;
        return;
    }

    emit sig_initFinished();
}

void CvUtils::cardCornerDetector::initSlots()
{
    // 连接内部信号槽，确保线程安全调用
    connect(this, &cardCornerDetector::sig_loadModel,
            this, &cardCornerDetector::slot_loadModel,
            Qt::QueuedConnection);

    connect(this, &cardCornerDetector::sig_detect,
            this, &cardCornerDetector::slot_detect,
            Qt::QueuedConnection);

    connect(this, &cardCornerDetector::sig_initFinished,
            this, [this]() {
                m_pythonProcessReady = true;
            }, Qt::QueuedConnection);

    connect(this, &cardCornerDetector::sig_exitProcess,
            this, &cardCornerDetector::slot_exitProcess,
            Qt::QueuedConnection);
}

void CvUtils::cardCornerDetector::registerMetaTypes()
{
    qRegisterMetaType<cv::Mat>("cv::Mat");
    qRegisterMetaType<CardDetectionResult>("CardDetectionResult");
    qRegisterMetaType<std::vector<CardDetectionResult>>("std::vector<CardDetectionResult>");
}

cv::Mat CvUtils::cardCornerDetector::drawResults(const cv::Mat &image, const std::vector<CardDetectionResult> &results)
{
    cv::Mat visualized = image.clone();
    if (visualized.empty()) return visualized;

    // 角点颜色
    const std::vector<cv::Scalar> cornerColors = {
        cv::Scalar(0, 0, 255), // 红色
        cv::Scalar(255, 0, 0), // 蓝色
        cv::Scalar(0, 255, 0), // 绿色
        cv::Scalar(0, 255, 255) // 黄色
    };

    for (const auto& res : results) {
        // 绘制边界框
        cv::rectangle(visualized, res.boundingBox, cv::Scalar(0, 255, 0), 2);

        // 绘制角点
        for (size_t i = 0; i < res.corners.size(); ++i) {
            cv::circle(visualized, res.corners[i], 5,
                       cornerColors[i % cornerColors.size()], -1);

            // 绘制角点序号
            cv::putText(visualized,
                        std::to_string(i + 1),
                        res.corners[i] + cv::Point2f(5, -5),
                        cv::FONT_HERSHEY_SIMPLEX, 0.5,
                        cornerColors[i % cornerColors.size()], 2);
        }

        // 绘制置信度
        std::string scoreText = cv::format("%.2f", res.confidence);
        cv::putText(visualized, scoreText,
                    cv::Point(res.boundingBox.x, res.boundingBox.y - 5),
                    cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 2);
    }

    return visualized;
}

QString CvUtils::cardCornerDetector::saveMatToTempFile(const cv::Mat &image, const QString &prefix)
{
    if (image.empty()) {
        emit sig_errorOccurred("临时文件保存失败: 输入图像为空");
        return "";
    }

    // 创建临时文件（前缀为 prefix，后缀为 .png，自动删除）
    QTemporaryFile tempFile("D:/Qt_Projects/GreatScanner/keypoint_detection/tempfile/" + prefix + "_XXXXXX.png");

    tempFile.setAutoRemove(false); // 手动控制删除（避免 Python 读取时文件已被删除）
    if (!tempFile.open()) {
        emit sig_errorOccurred("临时文件创建失败: " + tempFile.errorString());
        return "";
    }

    // 保存图像（PNG 格式无压缩，确保图像质量）
    QString tempPath = tempFile.fileName();
    tempFile.close(); // 关闭文件，允许 Python 读取
    cv::imwrite(tempPath.toStdString(), image);

    return tempPath;
}

std::vector<CardDetectionResult> CvUtils::cardCornerDetector::parseJsonResults(const json &jsonResults, const cv::Mat &sourceImage)
{
    std::vector<CardDetectionResult> results;
    if (jsonResults.empty()) return results;

    // 遍历每个检测结果
    for (const auto& item : jsonResults) {
        CardDetectionResult res;

        // 1. 解析边界框（JSON 中存储为 [x, y, width, height]，整数）
        int x = item["bbox"][0].get<int>();
        int y = item["bbox"][1].get<int>();
        int w = item["bbox"][2].get<int>();
        int h = item["bbox"][3].get<int>();
        res.boundingBox = cv::Rect(x, y, w, h);

        // 2. 解析置信度
        res.confidence = item["confidence"].get<float>();

        // 3. 解析角点（JSON 中存储为 [[x1,y1], [x2,y2], [x3,y3], [x4,y4]]，已排序）
        std::vector<cv::Point2f> corners;
        for (const auto& kpt : item["corners"]) {
            float cx = kpt[0].get<float>();
            float cy = kpt[1].get<float>();
            corners.emplace_back(cx, cy);
        }
        // 确保角点数量为 4（与标注一致）
        if (corners.size() == 4) {
            res.corners = corners;
            results.push_back(res);
        }
    }

    return results;
}

void CvUtils::cardCornerDetector::sendLoadModelCommand()
{
    if (!m_pythonProcess || m_pythonProcess->state() != QProcess::Running) {
        emit sig_errorOccurred("Python进程未运行，无法加载模型");
        return;
    }

    if (m_modelPath.isEmpty()) {
        emit sig_errorOccurred("模型路径为空，无法加载");
        return;
    }

    // 发送加载模型命令给Python进程（JSON格式便于解析）
    m_currentCommand = CommandType::LoadModel;
    json cmd;
    cmd["command"] = "load_model";
    cmd["model_path"] = m_modelPath.toStdString();
    QString cmdStr = QString::fromStdString(cmd.dump()) + "\n";

    m_pythonProcess->write(cmdStr.toUtf8());
}










